package com.feng.security.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.feng.common.api.ResultCode;
import com.feng.common.utils.Asserts;
import com.feng.common.utils.RedisCache;
import com.feng.common.utils.SecurityUtil;
import com.feng.security.config.SecurityConst;
import com.feng.security.domain.LoginUser;
import com.feng.security.dto.LoginBody;
import com.feng.security.service.AuthService;
import com.feng.security.utils.JwtUtil;
import com.feng.security.vo.LoginUserVO;
import com.feng.security.vo.VerificationCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Service;

/**
 * @author Feng
 * @since 2022/4/17 21:13
 */
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private RedisCache redisCache;

    @Override
    public String login(LoginBody loginBody) {
        String codeKey = SecurityConst.REDIS_CAPTCHA_KEY_PREFIX + loginBody.getUuid();
        String code = redisCache.getCacheObject(codeKey);
        redisCache.deleteObject(codeKey);
        if (StrUtil.isBlank(code)) {
            Asserts.fail("验证码已失效，请重新登录");
        }
        if (!StrUtil.equalsIgnoreCase(code, loginBody.getCode())) {
            Asserts.fail("验证码输入错误");
        }
        String username = loginBody.getUsername();
        String password = loginBody.getPassword();
        Boolean rememberMe = loginBody.getRememberMe();
        Authentication auth = null;
        try {
            auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
        } catch (DisabledException e) {
            Asserts.fail(ResultCode.USER_NOT_ENABLE);
        } catch (AuthenticationException e) {
            Asserts.fail(ResultCode.USERNAME_PWD_ERROR);
        }
        LoginUser loginUser = (LoginUser) auth.getPrincipal();
        String userId = loginUser.getUser().getUserId().toString();
        String userKey = SecurityConst.REDIS_JWT_KEY_PREFIX + userId;
        Long ttl = rememberMe != null && rememberMe ? SecurityConst.JWT_REMEMBER_ME_TTL : SecurityConst.JWT_DEFAULT_TTL;
        redisCache.setCacheObject(userKey, loginUser, ttl);
        return JwtUtil.createJWT(userId);
    }

    @Override
    public void logout() {
        Long userId = SecurityUtil.getCurrentUserDetails().getUser().getUserId();
        String redisKey = SecurityConst.REDIS_JWT_KEY_PREFIX + userId;
        redisCache.deleteObject(redisKey);
    }

    @Override
    public LoginUserVO info() {
        return new LoginUserVO(SecurityUtil.getCurrentUserDetails());
    }

    @Override
    public VerificationCode getCode() {
        ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(111, 36, 4, 4);
        String code = captcha.getCode();
        String codeImg = captcha.getImageBase64Data();
        String uuid = IdUtil.simpleUUID();
        redisCache.setCacheObject(SecurityConst.REDIS_CAPTCHA_KEY_PREFIX + uuid, code, SecurityConst.CAPTCHA_TTL);
        return new VerificationCode(codeImg, uuid);
    }
}
